﻿namespace Practices.SharePoint.Apps {
    using Microsoft.SharePoint;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.ServiceModel.Activation;

    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public class AppsService : IAppsService {
        private SPWeb clientWeb;

        #region Constructors

        public AppsService()
            : this(SPContext.Current != null ? SPContext.Current.Web : null) {
        }

        public AppsService(SPWeb clientWeb) {
            Validation.ArgumentNotNull(clientWeb, "clientWeb");

            this.clientWeb = clientWeb;
        }

        #endregion

        #region CRUD of App

        public string Create(string title, string launchUrl) {
            using (var catalogAccessor = new AppCatalogAccessor(clientWeb, true)) {
                return catalogAccessor.Create(title, launchUrl);
            }            
        }

        public string Upgrade(string title, string launchUrl, string productId) {
            using (var catalogAccessor = new AppCatalogAccessor(clientWeb, true)) {
                return catalogAccessor.Upgrade(title, launchUrl, new Guid(productId));
            }
        }

        public int Update(Dictionary<string, string> fields, string productId) {
            using (var catalogAccessor = new AppCatalogAccessor(clientWeb, true)) {
                return catalogAccessor.Update(fields, new Guid(productId));
            }
        }

        public bool Delete(string productId) {
            using (var catalogAccessor = new AppCatalogAccessor(clientWeb, true)) {
                return catalogAccessor.Delete(new Guid(productId));
            }            
        }

        #endregion

        #region Operations of AppInstance

        public string Push(string productId) {
            using (var catalogAccessor = new AppCatalogAccessor(clientWeb, true)) {
                SPListItem item = catalogAccessor.GetByProductId(new Guid(productId));

                var instance = clientWeb.GetAppInstancesByProductId(new Guid(productId)).FirstOrDefault();

                clientWeb.AllowUnsafeUpdates = true;
                if (instance == null) {
                    AppPackageFactory.RegisterPackage(item.File.OpenBinaryStream(), clientWeb);
                    instance = clientWeb.LoadAndInstallApp(item.File.OpenBinaryStream());
                } else {
                    if (new Version(item[AppBuiltInFields.Version].ToString()) > new Version(instance.App.VersionString)) {
                        instance.Upgrade(item.File.OpenBinaryStream());
                    }
                }
                clientWeb.AllowUnsafeUpdates = false;
                return instance.Id.ToString();
            }
            
        }

        public bool Pull(string productId) {
            var appInstances = clientWeb.GetAppInstancesByProductId(new Guid(productId));

            clientWeb.AllowUnsafeUpdates = true;
            foreach (var appInstance in appInstances) {
                appInstance.Uninstall();
            }
            clientWeb.AllowUnsafeUpdates = false;

            return true;
        }

        #endregion

        public string Generate(string title, string launchUrl, Dictionary<string, string> fields, string productId) {
            if (new Guid(productId).Equals(Guid.Empty)) {
                productId = Create(title, launchUrl);
            } else {
                Upgrade(title, launchUrl, productId);
            }
            Update(fields, productId);
            return Push(productId);
        }

        public bool Destroy(string productId) {
            Pull(productId);
            return Delete(productId);
        }
    }
}